/* Copyright 2014 Jan Wolter */

#include "stack.h"
#include "solve.h"
#include "waste.h"
#include "course.h"
#include "tableau.h"
#include "stock.h"

/* Array of stock piles used in this game */
StockStack *stock;
int stocksize= 0;	/* current size of stock array */

void makeStock(int dealto, int chunk, int passes, Stack *cards)
{
    /* Make sure we have memory for another stock pile */
    if (stocksize == 0)
    {
	stocksize= 1;
	stock= (StockStack *)malloc(stocksize*sizeof(StockStack));
    }
    else if (nstock == stocksize)
    {
	stocksize+= 1;
	stock= (StockStack *)realloc(stock,stocksize*sizeof(StockStack));
    }

    stock[nstock].dealto= dealto;
    stock[nstock].chunk= chunk;
    stock[nstock].passes= passes;

    /* Make it big enough for the cards array. mayInsert, firstMove,
     * and nextMove are all NULL because we can't move cards to or from
     * the stock (a deal is not a move) */
    int i= stock[nstock].id= newStack(STOCK,nstock,cards->n,
	    NULL, NULL, NULL, NULL);
    appendStack(stacks+i, cards, 0);

    nstock++;
}

void cleanStock()
{
    free(stock);
    nstock= stocksize= 0;
}

void printStock(FILE *f, Stack *stks)
{
    char label[8];
    for (int k= 0; k < nstock; k++)
    {
	sprintf(label,"S%02d", k+1);
	printStack(f,label, stks+stock[k].id);
    }
}

/* Is it possible to deal from the given stock? */
int mayDeal(int id)
{
    Stack *st= stacks+stock[id].id;
    return (st->n > 0 || stock[id].passes == 0 || passcnt < stock[id].passes);
}

/* Deal a card from the stock. Return true if we were able to deal a card.
 * If hist is not NULL, add entries describing what we did to the history
 * stack, with the given list of alternate moves.
 */
int dealStock(int id, Move **hist, Move *alt)
{
    Stack *st= stacks+stock[id].id;
    int ndst;
    int (*dstid)(int);
    void (*gatherdst)(Stack *, int);
    char dstc;

    if (stock[id].dealto == DT_TABLEAU)
    {
	if (st->n == 0) return 0;
	for (int k= 0; k < ntableau; k++)
	{
	    Card *c= popStack(st);
	    if (c == NULL) break;
	    movecnt++;
	    if (verbose > 2)
		printf("%3d: Dealt %s to T%d\n",movecnt, cardname(c), k+1);
	    if (hist)
	    {
		Move *m= newMove(MTYPE_STD,
		    stock[id].id, st->n, 1, tableau[k].id, 0, 0);
		m->prev= *hist;
		m->alt= alt;
		alt= NULL;
		*hist= m;
	    }
	    pushStack(stacks+tableau[k].id, c);
	}
	return 1;
    }

    if (stock[id].dealto == DT_WASTE)
    {
	dstc= 'W';
	ndst= nwaste;
	dstid= wasteid;
    }
    else /* DT_COURSE */
    {
	dstc= 'F';
	ndst= ncourse;
	dstid= courseid;
    }

    /* If stock is empty, flip the waste to make a new stock */
    if (st->n == 0)
    {
	if (stock[id].passes == 0 || passcnt < stock[id].passes)
	{
	    passcnt++;
	    for (int k= 0; k < ndst; k++)
	    {
		movecnt++;
		if (verbose > 2)
		    printf("%3d: W%02d -> S%02d (starting pass %d)\n",
			movecnt, k+1, id+1, passcnt);
		if (hist)
		{
		    int wid= (*dstid)(k);
		    Move *m= newMove(MTYPE_STD, wid, 0, stacks[wid].n,
			stock[id].id,0,0);
		    m->reverse= 1;
		    m->prev= *hist;
		    m->alt= alt;
		    alt= NULL;
		    *hist= m;
		}
	    }
	    if (stock[id].dealto == DT_WASTE)
		gatherWaste(st, 1);
	    else
		gatherCourse(st, 1);
	}
	else
	    return 0;
    }

    for (int i= 0; i < stock[id].chunk; i++)
    {
	for (int j= 0; j < ndst; j++)
	{
	    int wid= (*dstid)(j);

	    Card *c= popStack(st);
	    if (c == NULL) break;

	    movecnt++;
	    if (verbose > 2)
		printf("%3d: Dealt %s to %c%d\n",
			movecnt, cardname(c), dstc, j+1);
	    if (hist)
	    {
		Move *m= newMove(MTYPE_STD,
		    stock[id].id, st->n, 1, wid, 0, 0);
		m->prev= *hist;
		m->alt= alt;
		alt= NULL;
		*hist= m;
	    }
	    pushStack(stacks+wid, c);
	}
    }
    return 1;
}

/* Concatinate all cards from stock in their original order onto the given
 * stack. The stock is not altered.
 */
void gatherStock(Stack *s)
{
    for (int k= 0; k < nstock; k++)
    {
	Stack *ss= stacks+stock[k].id;
	appendStack(s, ss, 0);
    }
}
